#include <unittest++/UnitTest++.h>

#include "vector.h"
#include "matrix.h"
#include "framebuffer.h"
#include "object.h"
#include "scene.h"
#include "framebuffer.h"

#include <list>
#include <iostream>

TEST( vector_bracket ) {
    Vector vect;

    CHECK_EQUAL( 0.0, vect[0] );
    CHECK_EQUAL( 0.0, vect[1] );
    CHECK_EQUAL( 0.0, vect[2] );
    CHECK_EQUAL( 0.0, vect[3] );

    vect[2] = 1.0;

    CHECK_EQUAL( 0.0, vect[0] );
    CHECK_EQUAL( 0.0, vect[1] );
    CHECK_EQUAL( 1.0, vect[2] );
    CHECK_EQUAL( 1.0, vect.at(2) );
    CHECK_EQUAL( 0.0, vect[3] );
}
TEST( vector_addition ) {
    Vector vect, vect2, vect3;

    vect[0] = 2.0;
    vect[1] = 1.0;
    vect[3] = 4.0;

    vect2[0] = -2.0;
    vect2[1] = -1.0;
    vect2[3] = -4.0;

    CHECK_EQUAL( vect3, vect + vect2 );

    CHECK( !vect.equals( vect2, 0.000000001 ) );

    vect += vect2;

    CHECK_EQUAL( vect3, vect );
}
TEST( vector_subtraction ) {
    Vector vect, vect2, vect3;

    vect[0] = 2.0;
    vect[1] = 1.0;
    vect[3] = 4.0;

    vect2[0] = 2.0;
    vect2[1] = 1.0;
    vect2[3] = 4.0;

    CHECK_EQUAL( vect3, vect - vect2 );

    CHECK( !vect.equals( vect3, 0.000000001 ) );

    vect -= vect2;

    CHECK_EQUAL( vect3, vect );
}
TEST( vector_unary ) {
    Vector vect, vect2;

    vect[0] = 2.0;
    vect[1] = 1.0;
    vect[3] = 4.0;

    vect2[0] = -2.0;
    vect2[1] = -1.0;
    vect2[3] = -4.0;

    CHECK_EQUAL( vect, -vect2 );
}
TEST( vector_scale ) {
    Vector vect, vect2;

    vect[0] = 1;
    vect[1] = 2;
    vect[2] = 4;

    vect2[0] = 2;
    vect2[1] = 4;
    vect2[2] = 8;

    CHECK_EQUAL( vect2, vect * 2 );
    CHECK_EQUAL( vect, vect2 / 2 );
}
TEST( vector_dotProduct ) {
    Vector vect;

    CHECK_EQUAL( 0.0, Vector::dotProduct( vect, vect ) );

    vect[0] = 1;

    CHECK_EQUAL( 1.0, Vector::dotProduct( vect, vect ) );
}
TEST( vector_normalize ) {
    Vector vect, vect2;

    vect[0] = 1;
    vect2[0] = 2;

    vect2.normalize();

    CHECK_EQUAL( vect, vect2 );

    vect2[0] = 2;

    CHECK_EQUAL( vect, Vector::normalize( vect2 ) );
}

TEST( matrix_bracket ) {
    Matrix mat;

    mat[0] = 1.0;
    mat[2] = 2.0;

    CHECK_EQUAL( 1.0, mat.at( 0 ) );
    CHECK_EQUAL( 2.0, mat.at( 2 ) );
    CHECK_EQUAL( 1.0, mat.at( 0, 0 ) );
    CHECK_EQUAL( 2.0, mat.at( 0, 2 ) );
}
TEST( matrix_multiply ) {
    Matrix a, b, temp;

    for( int i = 0; i < 4; i++ ) {
        for ( int j = 0; j < 4; j++ ) {
            a.set( i, j, (i + 1) * (j + 1) + 4 - i * (4 - j) );
            b.set( j, i, (i + 1) * (j + 1) + 4 - i * (4 - j) );
        }
    }

    temp[0] = 174.0;
    temp[1] = 184.0;
    temp[2] = 194.0;
    temp[3] = 204.0;
    temp[4] = 184.0;
    temp[5] = 214.0;
    temp[6] = 244.0;
    temp[7] = 274.0;
    temp[8] = 194.0;
    temp[9] = 244.0;
    temp[10] = 294.0;
    temp[11] = 344.0;
    temp[12] = 204.0;
    temp[13] = 274.0;
    temp[14] = 344.0;
    temp[15] = 414.0;

    CHECK( !a.equals( temp, 0.000000001) );

    CHECK_EQUAL( temp, a * b );

    a *= b;

    CHECK_EQUAL( temp, a );
    CHECK( a.equals( temp, 0.000000001) );
}
TEST( matrix_vectormultiply ) {
    Vector av, bv, temp;
    Matrix a, b;

    for( int i = 0; i < 4; i++ ) {
        av[i] = i + 1;
        for ( int j = 0; j < 4; j++ ) {
            a[ i * 4 + j ] = (i + 1) * (j + 1) + 4 - i * (4 - j);
        }
    }

    bv[0] = 70.0;
    bv[1] = 80.0;
    bv[2] = 90.0;
    bv[3] = 100.0;

    temp = a * av;

    CHECK( temp.equals( bv, 0.00000000001 ) );
}

TEST( framebuffer_clear ) {
    FrameBuffer fb( 500, 500 );
    fb.clear( 0.0, 0.0, 1.0 );
    fb.writeBitmap( "red.bmp" );
}
TEST( photonlist ) {
    Photon p;
    LinkedList<Photon> list;

    for( unsigned int i = 0; i < 50; i++ ) {
        list.add( p );
    }

    LinkedList<Photon>::iterator iter = list.begin();
    unsigned int i = 0;

    while( iter != list.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 50, i );

    LinkedList<Photon> test( list );

    i = 0;

    iter = test.begin();
    while( iter != test.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 50, i );

    LinkedList<Photon> test2;
    test2 = test;

    i = 0;
    iter = test2.begin();
    while( iter != test2.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 50, i );

    list.clear();

    i = 0;
    iter = list.begin();
    while( iter != list.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 0, i );

    i = 0;
    iter = test2.begin();
    while( iter != test2.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 50, i );

    i = 0;

    iter = test.begin();
    while( iter != test.end() ) {
        iter++;
        i++;
    }

    CHECK_EQUAL( 50, i );
}

int main() {
    return UnitTest::RunAllTests();
}
